using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using OracleInternal.I18N;
using OracleInternal.Network;
using OracleInternal.TTC;
using OracleInternal.TTC.Accessors;

namespace OracleInternal.ServiceObjects
{
	internal class DataUnmarshaller
	{
		private const int TTCC_MXL = 252;

		internal const int TTCC_ESC = 253;

		internal const int TTCC_LNG = 254;

		internal const int TTCC_ERR = 255;

		internal const int TTCC_MXIN_NEW = 32767;

		internal const int TTCC_MXIN_OLD = 64;

		internal int m_effectiveTTCC_MXIN = 64;

		internal bool m_bUseBigCLRChunks;

		internal TTCTypeRepresentation m_typeRepresentation;

		private OraArraySegment m_currentSegment;

		internal int m_currentSegmentIndex;

		internal byte[] m_currentSegmentArray;

		internal int m_positionInCurrentSegment;

		internal List<ArraySegment<byte>> m_dataSegments;

		internal long m_DataLeftInCurrentSegment;

		internal bool m_bAccumulateByteSegments;

		internal int[] m_colDataStartOffset;

		internal int[] m_indexOfOASArray;

		internal OraArraySegment[] m_oraArrSegWithColRowInfo;

		internal int m_oraArrSegCount;

		internal int m_oraArrSegWithColRowInfoIndex;

		internal int m_bFirstNonNullOraArrSegWithColInfoEntry;

		internal int m_indexOfLastOraArrSegUsed;

		internal OraColumnData[] m_duplicateDataStore;

		internal int m_columnCount;

		internal char[] m_charArrayForConversion;

		internal char[] m_charArrayForBigDataConversion;

		internal DataUnmarshaller(MarshallingEngine mEngine)
		{
			m_typeRepresentation = mEngine.m_typeRepresentation;
			m_bUseBigCLRChunks = mEngine.m_bUseBigCLRChunks;
		}

		internal char[] GetCharArrayForConversion(long numBytesFetched, Conv conversion)
		{
			char[] array = null;
			long num = numBytesFetched / conversion.MinBytesPerChar;
			if (m_charArrayForConversion != null)
			{
				if (num > m_charArrayForConversion.Length)
				{
					if (m_charArrayForBigDataConversion == null || num > m_charArrayForBigDataConversion.Length)
					{
						m_charArrayForBigDataConversion = new char[num];
					}
					return m_charArrayForBigDataConversion;
				}
				return m_charArrayForConversion;
			}
			return new char[num];
		}

		internal short UnmarshalUB1()
		{
			if (m_DataLeftInCurrentSegment <= 0)
			{
				MoveToNextArraySegment();
			}
			int num = m_currentSegmentArray[m_positionInCurrentSegment] & 0xFF;
			m_positionInCurrentSegment++;
			m_DataLeftInCurrentSegment--;
			return (short)num;
		}

		internal int UnmarshalUB2()
		{
			return (int)(BufferToValue(1) & 0xFFFF);
		}

		internal long UnmarshalUB4()
		{
			return BufferToValue(2);
		}

		internal int UnmarshalSB4()
		{
			return (int)UnmarshalUB4();
		}

		internal long UnmarshalSB8()
		{
			return BufferToValue(3);
		}

		private long BufferToValue(byte repOffset)
		{
			byte[] dataBuffer = null;
			int offset = 0;
			int bufLength = 0;
			long num = 0L;
			bool flag = false;
			byte b = m_typeRepresentation.m_representationArray[repOffset];
			flag = ReadLengthAndData(repOffset, b, out dataBuffer, ref offset, ref bufLength);
			switch (bufLength)
			{
			case 1:
				num = dataBuffer[offset];
				break;
			case 2:
				num = (((b & 2) <= 0) ? (dataBuffer[offset + 1] | (dataBuffer[offset] << 8)) : (dataBuffer[offset] | (dataBuffer[offset + 1] << 8)));
				break;
			case 3:
				num = (((b & 2) <= 0) ? (dataBuffer[offset + 2] | (dataBuffer[offset + 1] << 8) | (dataBuffer[offset] << 16)) : (dataBuffer[offset] | (dataBuffer[offset + 1] << 8) | (dataBuffer[offset + 2] << 16)));
				break;
			case 4:
				num = (((b & 2) <= 0) ? (dataBuffer[offset + 3] | (dataBuffer[offset + 2] << 8) | (dataBuffer[offset + 1] << 16) | (dataBuffer[offset] << 24)) : (dataBuffer[offset] | (dataBuffer[offset + 1] << 8) | (dataBuffer[offset + 2] << 16) | (dataBuffer[offset + 3] << 24)));
				break;
			case 5:
				num = (((b & 2) <= 0) ? (dataBuffer[offset + 4] | (dataBuffer[offset + 3] << 8) | (dataBuffer[offset + 2] << 16) | (dataBuffer[offset + 1] << 24) | dataBuffer[offset]) : (dataBuffer[offset] | (dataBuffer[offset + 1] << 8) | (dataBuffer[offset + 2] << 16) | (dataBuffer[offset + 3] << 24) | dataBuffer[offset + 4]));
				break;
			case 6:
				num = (((b & 2) <= 0) ? (dataBuffer[offset + 5] | (dataBuffer[offset + 4] << 8) | (dataBuffer[offset + 3] << 16) | (dataBuffer[offset + 2] << 24) | dataBuffer[offset + 1] | (dataBuffer[offset] << 8)) : (dataBuffer[offset] | (dataBuffer[offset + 1] << 8) | (dataBuffer[offset + 2] << 16) | (dataBuffer[offset + 3] << 24) | dataBuffer[offset + 4] | (dataBuffer[offset + 5] << 8)));
				break;
			case 7:
				num = (((b & 2) <= 0) ? (dataBuffer[offset + 6] | (dataBuffer[offset + 5] << 8) | (dataBuffer[offset + 4] << 16) | (dataBuffer[offset + 3] << 24) | dataBuffer[offset + 2] | (dataBuffer[offset + 1] << 8) | (dataBuffer[offset] << 16)) : (dataBuffer[offset] | (dataBuffer[offset + 1] << 8) | (dataBuffer[offset + 2] << 16) | (dataBuffer[offset + 3] << 24) | dataBuffer[offset + 4] | (dataBuffer[offset + 5] << 8) | (dataBuffer[offset + 6] << 16)));
				break;
			case 8:
				num = (((b & 2) <= 0) ? (dataBuffer[offset + 7] | (dataBuffer[offset + 6] << 8) | (dataBuffer[offset + 5] << 16) | (dataBuffer[offset + 4] << 24) | dataBuffer[offset + 3] | (dataBuffer[offset + 2] << 8) | (dataBuffer[offset + 1] << 16) | (dataBuffer[offset] << 24)) : (dataBuffer[offset] | (dataBuffer[offset + 1] << 8) | (dataBuffer[offset + 2] << 16) | (dataBuffer[offset + 3] << 24) | dataBuffer[offset + 4] | (dataBuffer[offset + 5] << 8) | (dataBuffer[offset + 6] << 16) | (dataBuffer[offset + 7] << 24)));
				break;
			}
			if (flag)
			{
				num = -num;
			}
			return num;
		}

		internal void UnmarshalCLR_ScanOnly(int maxSize, ref int length)
		{
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			bool flag = false;
			try
			{
				length = 0;
				int num5 = -1;
				int num6 = UnmarshalUB1();
				if (num6 < 0)
				{
					throw new Exception("TTC Error");
				}
				if (EscapeSequenceNull(num6))
				{
					length = 0;
					return;
				}
				if (num6 != 254)
				{
					if (num6 > 0)
					{
						num3 = ((maxSize < num6) ? maxSize : num6);
						num2 = UnmarshalBuffer_ScanOnly(num3);
						num4 += num3;
						int num7 = num6 - num3;
						if (num7 > 0)
						{
							UnmarshalBuffer_ScanOnly(num7);
						}
					}
					return;
				}
				num5 = -1;
				bool flag2 = false;
				while (!flag2)
				{
					if (num5 != -1)
					{
						num6 = ((!m_bUseBigCLRChunks) ? UnmarshalUB1() : UnmarshalSB4());
						if (num6 <= 0)
						{
							flag2 = true;
							continue;
						}
					}
					if (num6 == 254)
					{
						switch (num5)
						{
						case -1:
							num5 = 1;
							continue;
						case 1:
							num5 = 0;
							break;
						case 0:
							if (flag)
							{
								num5 = 0;
								break;
							}
							num5 = 0;
							continue;
						}
					}
					if (num2 == -1)
					{
						UnmarshalBuffer_ScanOnly(num6);
					}
					else
					{
						num = num6;
						if (num > 0)
						{
							num3 = ((maxSize - num4 < num) ? (maxSize - num4) : num);
							num2 = UnmarshalBuffer_ScanOnly(num3);
							num4 += num3;
							int num8 = num - num3;
							if (num8 > 0)
							{
								UnmarshalBuffer_ScanOnly(num8);
							}
						}
					}
					num5 = 0;
					if (num6 > 252)
					{
						flag = true;
					}
				}
			}
			finally
			{
				length = num4;
			}
		}

		internal void UnmarshalCLR(int maxSize, byte[] buffer, ref int length)
		{
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			bool flag = false;
			try
			{
				length = 0;
				int num5 = -1;
				int num6 = UnmarshalUB1();
				if (num6 < 0)
				{
					throw new Exception("TTC Error");
				}
				if (EscapeSequenceNull(num6))
				{
					length = 0;
					return;
				}
				if (num6 != 254)
				{
					if (num6 > 0)
					{
						num3 = ((maxSize < num6) ? maxSize : num6);
						num2 = UnmarshalBuffer(buffer, num2, num3);
						num4 += num3;
						int num7 = num6 - num3;
						if (num7 > 0)
						{
							UnmarshalBuffer(null, 0, num7);
						}
					}
					return;
				}
				num5 = -1;
				bool flag2 = false;
				while (!flag2)
				{
					if (num5 != -1)
					{
						num6 = ((!m_bUseBigCLRChunks) ? UnmarshalUB1() : UnmarshalSB4());
						if (num6 <= 0)
						{
							flag2 = true;
							continue;
						}
					}
					if (num6 == 254)
					{
						switch (num5)
						{
						case -1:
							num5 = 1;
							continue;
						case 1:
							num5 = 0;
							break;
						case 0:
							if (flag)
							{
								num5 = 0;
								break;
							}
							num5 = 0;
							continue;
						}
					}
					if (num2 == -1)
					{
						UnmarshalBuffer_ScanOnly(num6);
					}
					else
					{
						num = num6;
						if (num > 0)
						{
							num3 = ((maxSize - num4 < num) ? (maxSize - num4) : num);
							num2 = UnmarshalBuffer(buffer, num2, num3);
							num4 += num3;
							int num8 = num - num3;
							if (num8 > 0)
							{
								UnmarshalBuffer(null, 0, num8);
							}
						}
					}
					num5 = 0;
					if (num6 > 252)
					{
						flag = true;
					}
				}
			}
			finally
			{
				length = num4;
			}
		}

		internal int UnmarshalBuffer_ScanOnly(int len)
		{
			int num = Read(null, 0, len);
			if (num < 0)
			{
				throw new Exception("TTC Error");
			}
			return num;
		}

		internal int UnmarshalBuffer(byte[] buffer, int offset, int len)
		{
			int num = 0;
			if ((num = Read(buffer, offset, len)) < 0)
			{
				throw new Exception("TTC Error");
			}
			return offset + num;
		}

		internal bool EscapeSequenceNull(int bytes)
		{
			bool result = false;
			switch (bytes)
			{
			case 0:
				result = true;
				break;
			case 253:
				throw new Exception("TTC Error");
			case 255:
				result = true;
				break;
			}
			return result;
		}

		internal int Read(byte[] userBuffer, int offset, int length)
		{
			int num = 0;
			do
			{
				if (m_DataLeftInCurrentSegment <= 0)
				{
					MoveToNextArraySegment();
				}
				num += GetData(userBuffer, offset + num, length - num);
			}
			while (num < length);
			return num;
		}

		internal bool ReadLengthAndData(byte repOffset, byte typeRep, out byte[] dataBuffer, ref int offset, ref int bufLength)
		{
			bool result = false;
			dataBuffer = null;
			offset = 0;
			if ((typeRep & 1) > 0)
			{
				if (m_DataLeftInCurrentSegment <= 0)
				{
					MoveToNextArraySegment();
				}
				bufLength = m_currentSegmentArray[m_positionInCurrentSegment] & 0xFF;
				m_positionInCurrentSegment++;
				m_DataLeftInCurrentSegment--;
				if ((bufLength & 0x80) > 0)
				{
					bufLength &= 127;
					result = true;
				}
				if (bufLength < 0)
				{
					throw new Exception("TTC Error");
				}
				if (bufLength == 0)
				{
					dataBuffer = null;
					bufLength = 0;
					return result;
				}
				if ((repOffset == 1 && bufLength > 2) || (repOffset == 2 && bufLength > 4) || (repOffset == 3 && bufLength > 8))
				{
					throw new Exception("TTC Error");
				}
			}
			else
			{
				switch (repOffset)
				{
				case 1:
					bufLength = 2;
					break;
				case 2:
					bufLength = 4;
					break;
				case 3:
					bufLength = 8;
					break;
				}
			}
			if (m_DataLeftInCurrentSegment <= 0)
			{
				MoveToNextArraySegment();
			}
			dataBuffer = null;
			offset = 0;
			if (m_DataLeftInCurrentSegment >= bufLength)
			{
				dataBuffer = m_currentSegmentArray;
				offset = m_positionInCurrentSegment;
				m_positionInCurrentSegment += bufLength;
				m_DataLeftInCurrentSegment -= bufLength;
			}
			else
			{
				dataBuffer = new byte[bufLength];
				Read(dataBuffer, 0, bufLength);
			}
			return result;
		}

		private void MoveToNextArraySegment()
		{
			m_currentSegment = m_oraArrSegWithColRowInfo[m_oraArrSegWithColRowInfoIndex++];
			m_indexOfLastOraArrSegUsed = m_oraArrSegWithColRowInfoIndex - 1;
			m_currentSegmentArray = m_currentSegment.Array;
			m_positionInCurrentSegment = m_currentSegment.Offset;
			m_DataLeftInCurrentSegment = m_currentSegment.Count;
		}

		internal int GetData(byte[] userBuffer, int offset, int length)
		{
			int num = 0;
			if (m_DataLeftInCurrentSegment > 0)
			{
				num = (int)((length <= (int)m_DataLeftInCurrentSegment) ? length : m_DataLeftInCurrentSegment);
				if (userBuffer != null)
				{
					Buffer.BlockCopy(m_currentSegmentArray, m_positionInCurrentSegment, userBuffer, offset, num);
				}
				else if (m_bAccumulateByteSegments)
				{
					m_dataSegments.Add(new ArraySegment<byte>(m_currentSegmentArray, m_positionInCurrentSegment, num));
				}
				m_positionInCurrentSegment += num;
				m_DataLeftInCurrentSegment -= num;
			}
			return num;
		}

		internal bool DuplicateDataExistsForLastRow(int colIndex)
		{
			if (m_duplicateDataStore != null)
			{
				return m_duplicateDataStore[colIndex] != null;
			}
			return false;
		}

		internal void SaveAllDuplicateColumnsFromLastRow(TTCRowData rowData, Accessor[] accessors, int noOfRowsFetchedLastTime)
		{
			int numberOfColumns = rowData.m_numberOfColumns;
			BitArray bitArrayOfColumns = rowData.m_bitArrayOfColumns;
			if (m_duplicateDataStore == null || m_duplicateDataStore.Length < numberOfColumns)
			{
				m_duplicateDataStore = new OraColumnData[numberOfColumns];
			}
			for (int i = 0; i < numberOfColumns; i++)
			{
				if (!bitArrayOfColumns.Get(i))
				{
					OraColumnData oraColumnData = m_duplicateDataStore[i];
					int num = (noOfRowsFetchedLastTime - 1) * numberOfColumns + i;
					int num2 = m_colDataStartOffset[num];
					if (num2 >= 0)
					{
						if (oraColumnData == null)
						{
							oraColumnData = new OraColumnData();
							m_duplicateDataStore[i] = oraColumnData;
						}
						oraColumnData.m_rawData = accessors[i].GetByteRepresentation(this, noOfRowsFetchedLastTime - 1, i);
						oraColumnData.m_netTypeData = null;
						oraColumnData.m_rowNum = 0;
					}
					else if (num2 == -1)
					{
						m_duplicateDataStore[i] = null;
					}
					else if (num2 == -2)
					{
						oraColumnData.m_rowNum = 0;
					}
					else if (num2 <= -20)
					{
						int num3 = -1 * (num2 - -20);
						if (oraColumnData == null || oraColumnData.m_rowNum != num3)
						{
							oraColumnData = new OraColumnData();
							m_duplicateDataStore[i] = oraColumnData;
							oraColumnData.m_rawData = accessors[i].GetByteRepresentation(this, num3, i);
							oraColumnData.m_netTypeData = null;
							oraColumnData.m_rowNum = 0;
						}
						else
						{
							oraColumnData.m_rowNum = 0;
						}
					}
				}
				else
				{
					m_duplicateDataStore[i] = null;
				}
			}
		}

		internal bool NextRowHasDuplicateData(int currentRow, int columnIndex)
		{
			int num = (currentRow + 1) * m_columnCount + columnIndex;
			return m_colDataStartOffset[num] <= -20;
		}

		internal void SaveColumnData(int currentRow, int columnIndex, byte[] rawData, object netTypeData, bool bCopyRawData)
		{
			int num = (currentRow + 1) * m_columnCount + columnIndex;
			if (m_colDataStartOffset[num] <= -20)
			{
				if (m_duplicateDataStore == null || m_duplicateDataStore.Length < m_columnCount)
				{
					m_duplicateDataStore = new OraColumnData[m_columnCount];
				}
				OraColumnData oraColumnData;
				if ((oraColumnData = m_duplicateDataStore[columnIndex]) == null)
				{
					oraColumnData = new OraColumnData();
				}
				oraColumnData.m_rawData = rawData;
				oraColumnData.m_netTypeData = netTypeData;
				oraColumnData.m_rowNum = currentRow;
				m_duplicateDataStore[columnIndex] = oraColumnData;
			}
		}

		internal bool TryGetValueIfDuplicate(int currentRow, int columnIndex, out OraColumnData oraColData)
		{
			oraColData = null;
			bool result = false;
			int num = 0;
			if (m_duplicateDataStore == null)
			{
				return result;
			}
			_ = m_columnCount;
			num = m_colDataStartOffset[currentRow * m_columnCount + columnIndex];
			if (num == -2)
			{
				oraColData = m_duplicateDataStore[columnIndex];
				result = true;
			}
			else if (num <= -20)
			{
				int num2 = -1 * (num - -20);
				if (m_duplicateDataStore != null && (oraColData = m_duplicateDataStore[columnIndex]) != null)
				{
					if (oraColData.m_rowNum == num2)
					{
						result = true;
					}
					else
					{
						oraColData = null;
					}
				}
			}
			return result;
		}

		internal bool TryGetValueIfDuplicateInDataSet(int currentRow, int columnIndex, DataTable table, string columnName, out object oraColData)
		{
			oraColData = null;
			bool result = false;
			int num = 0;
			if (table == null)
			{
				return result;
			}
			int num2 = currentRow * m_columnCount + columnIndex;
			num = m_colDataStartOffset[num2];
			if (num <= -20 || num == -2)
			{
				bool flag = false;
				if (columnName.StartsWith("\"") && columnName.EndsWith("\""))
				{
					flag = true;
					columnName = columnName.Trim('"');
				}
				if (string.Compare(columnName, table.Columns[columnIndex].ColumnName) == 0 || (!flag && string.Compare(columnName, table.Columns[columnIndex].ColumnName, StringComparison.InvariantCultureIgnoreCase) == 0))
				{
					oraColData = table.Rows[table.Rows.Count - 1][columnIndex];
				}
				else
				{
					oraColData = table.Rows[table.Rows.Count - 1][columnName];
				}
				result = true;
			}
			return result;
		}

		internal void StartAccumulatingColumnData(int currentRow, int columnIndex, List<ArraySegment<byte>> rowDataSegments)
		{
			int num = currentRow * m_columnCount + columnIndex;
			int num2 = m_colDataStartOffset[num];
			if (num2 < 0)
			{
				if (currentRow == 0)
				{
					return;
				}
				if (num2 <= -20)
				{
					num = -1 * (num2 - -20) * m_columnCount + columnIndex;
				}
			}
			m_oraArrSegWithColRowInfoIndex = m_indexOfOASArray[num];
			m_currentSegment = m_oraArrSegWithColRowInfo[m_oraArrSegWithColRowInfoIndex++];
			m_currentSegmentArray = m_currentSegment.Array;
			m_positionInCurrentSegment = m_colDataStartOffset[num];
			m_DataLeftInCurrentSegment = m_currentSegment.Offset + m_currentSegment.Count - m_positionInCurrentSegment;
			m_bAccumulateByteSegments = true;
			m_dataSegments = rowDataSegments;
		}

		internal void StopAccumulatingColumnData()
		{
			m_bAccumulateByteSegments = false;
			if (m_dataSegments != null)
			{
				m_dataSegments.Clear();
				m_dataSegments = null;
			}
		}

		internal static void ReleaseAllOBs(OraArraySegment[] oasArray, int arrLength, OracleCommunication orclComm)
		{
			for (int i = 0; i < arrLength; i++)
			{
				OraArraySegment oraArraySegment = oasArray[i];
				if (oraArraySegment == null)
				{
					continue;
				}
				oraArraySegment.m_maxRowNum = -1;
				oasArray[i] = null;
				if (oraArraySegment.m_bInUseByTTCLayer)
				{
					for (int j = 0; j < oraArraySegment.OB.the_ByteSegments_Count; j++)
					{
						oraArraySegment.OB.the_ByteSegments[j].m_bInUseByTTCLayer = false;
					}
					orclComm.OraBufPool.Put(oraArraySegment.OB.size, oraArraySegment.OB);
				}
			}
		}

		internal void TryOraBufRelease(int currRowNum, OracleCommunication orclComm)
		{
			if (currRowNum == 0)
			{
				return;
			}
			int bFirstNonNullOraArrSegWithColInfoEntry = ((m_bFirstNonNullOraArrSegWithColInfoEntry > 0) ? m_bFirstNonNullOraArrSegWithColInfoEntry : 0);
			for (int i = m_bFirstNonNullOraArrSegWithColInfoEntry; i < m_oraArrSegCount; i++)
			{
				OraArraySegment oraArraySegment = m_oraArrSegWithColRowInfo[i];
				if (oraArraySegment == null)
				{
					continue;
				}
				if (oraArraySegment.m_maxRowNum >= currRowNum - 1)
				{
					break;
				}
				oraArraySegment.m_maxRowNum = -1;
				oraArraySegment.m_bInUseByTTCLayer = false;
				m_oraArrSegWithColRowInfo[i] = null;
				bFirstNonNullOraArrSegWithColInfoEntry = i + 1;
				bool flag = false;
				for (int j = 0; j < oraArraySegment.OB.the_ByteSegments_Count; j++)
				{
					if (oraArraySegment.OB.the_ByteSegments[j].m_bInUseByTTCLayer)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					orclComm.OraBufPool.Put(oraArraySegment.OB.size, oraArraySegment.OB);
				}
			}
			m_bFirstNonNullOraArrSegWithColInfoEntry = bFirstNonNullOraArrSegWithColInfoEntry;
		}
	}
}
